package com.zmn.oms.business.impl.masterphoto;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.zmn.biz.ais.common.consts.ImageDetectionConsts;
import com.zmn.biz.ais.common.dio.img.ImageDetectionDIO;
import com.zmn.biz.ais.dubbo.interfaces.img.ImageDetectionRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.crypt.MD5Utils;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.oms.business.interfaces.conf.attachment.ConfOrderAttachmentBService;
import com.zmn.oms.business.interfaces.masterphoto.OrderPhotoBService;
import com.zmn.oms.business.interfaces.messageV1.app.MessageSendAppService;
import com.zmn.oms.common.annotation.OrderWorkCasOperate;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.dto.order.photo.OrderPhotoDetectionDTO;
import com.zmn.oms.model.dto.order.photo.OrderPhotoDetectionResultDTO;
import com.zmn.oms.model.dto.work.modify.OrderPhotoDTO;
import com.zmn.oms.model.entity.conf.attachment.ConfOrderAttachment;
import com.zmn.oms.model.entity.conf.attachment.ConfOrderAttachmentAuditStandard;
import com.zmn.oms.model.entity.conf.attachment.ConfOrderAttachmentCategory;
import com.zmn.oms.model.entity.conf.attachment.ConfOrderAttachmentStandard;
import com.zmn.oms.model.entity.orderattachment.OrderAttachment;
import com.zmn.oms.model.entity.orderattachment.OrderAttachmentQuery;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.conf.attachment.ConfOrderAttachmentCategoryService;
import com.zmn.oms.services.interfaces.conf.attachment.ConfOrderAttachmentStandardService;
import com.zmn.oms.services.interfaces.order.OrderExtendService;
import com.zmn.oms.services.interfaces.orderattachment.OrderAttachmentService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * @author: SongWeidong
 * @description: 工程师拍照
 * @create: 2019-07-12 14:02
 **/
@Service
public class OrderPhotoBServiceImpl implements OrderPhotoBService {

    private Logger logger = LoggerFactory.getLogger(OrderPhotoBService.class);

    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderExtendService orderExtendService;
    @Resource
    private ZmnMQSender zmnMQSender;
    @Resource
    private OrderPhotoBService orderPhotoBService;
	@Resource
	private MessageSendAppService messageSendAppService;
    @Resource
    private OrderAttachmentService orderAttachmentService;
    @Resource
    private ConfOrderAttachmentStandardService confOrderAttachmentStandardService;
    @Resource
    private ConfOrderAttachmentBService confOrderAttachmentBService;
	@Resource
	private ConfOrderAttachmentCategoryService confOrderAttachmentCategoryService;

    @Reference(version = com.zmn.tapi.dubbo.DubboConsts.INTERFACE_VERSION, check = false)
    private ImageDetectionRemoteService imageDetectionRemoteService;

    // 附件发送审核请求时的ID
    private static final String REQUEST_ID_FORMAT = "%s-%s-%s-%s";

    @Override
    @Transactional(rollbackFor = Exception.class)
    @OrderWorkCasOperate(type = OrderConsts.ORDER_OP_TYPE_ORDER_PHOTO)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_ORDER_PHOTO, beforeProceed = false)
    public void updateOrderPhoto(OrderPhotoDTO orderPhotoDTO) {

        // 批量更新附件照片
	    List<OrderAttachment> attachmentList = orderPhotoDTO.getAttachmentList();
	    if (CollectionUtil.isNotNullOrEmpty(attachmentList)) {
		    attachmentList.forEach(attachmentItem -> {
			    // 更新附件
			    attachmentItem.setOrderId(orderPhotoDTO.getOrderId());
			    attachmentItem.setReviewerId(orderPhotoDTO.getOperatorId());
			    attachmentItem.setReviewTime(DateUtil.getNow());
			    attachmentItem.setCreater(orderPhotoDTO.getOperator());
			    attachmentItem.setUpdater(orderPhotoDTO.getOperator());
			    orderAttachmentService.updateByKey(attachmentItem);
		    });

			OrderAttachment orderAttachment = attachmentList.stream().filter(item -> Objects.equals(item.getType(), OrderAttachmentTypeEnum.CONSTS_THZ)).findAny().orElse(null);
			if (orderAttachment != null) {
				// 修改工单的贴花状态
				OrderWork updateOrderWork = new OrderWork();
				updateOrderWork.setOrderId(orderPhotoDTO.getOrderId());
				updateOrderWork.setWorkId(orderPhotoDTO.getWorkId());
				updateOrderWork.setAppliqueStatus(orderAttachment.getReviewStatus());
				orderWorkService.updateOrderWorkByKey(updateOrderWork);
			}
	    }
    }

	@Override
	public void sendImageDetectionRequest(OrderPhotoDetectionDTO dto) throws OmsBaseException {
		OrderWork orderWork = orderWorkService.findOrderWorkByKey(dto.getOrderId(), dto.getWorkId());

		// 检查是否可以操作工单照片
		this.checkCanOperation(orderWork);

		OrderAttachment attachment = orderAttachmentService.findAttachmentByKey(dto.getAttachmentId());

		if(Objects.isNull(attachment)){
			logger.warn("发送自动审核请求失败！工单号：[{}] ，未查询出附件 入参：[{}]", dto.getWorkId(), dto);
			return;
		}

		// 获取照片配置
		OrderAttachmentQuery orderAttachmentQuery = BeanMapper.map(orderWork, OrderAttachmentQuery.class);
		// 后台配置的是前台产品
		orderAttachmentQuery.setProductId(orderWork.getShowProductId());
		orderAttachmentQuery.setType(dto.getPictureType());
		ConfOrderAttachment photoConfigAttachment = confOrderAttachmentBService.getAttachmentConfigByQuery(orderAttachmentQuery);

		if (Objects.isNull(photoConfigAttachment)) {
			logger.warn("请确认照片ID：[{}] 是否配置了照片配置", dto.getPictureType());
			return;
		}

		// 检查是否同时开启【后台审核】与【自动审核】
		if (!(Objects.equals(photoConfigAttachment.getNeedReview(), GlobalConsts.YES)
				&& Objects.equals(photoConfigAttachment.getAutoAudit(), GlobalConsts.YES))) {
			logger.warn("请确认照片配置ID：[{}]，是否开启了【后台审核】与【自动审核】功能", photoConfigAttachment.getId());
			return;
		}

		// 验证该【照片配置】是否有【审核标准】
		this.getAttachmentStandard(orderWork, photoConfigAttachment);

		// 调用自动审核异步接口
		this.sendRequest(attachment.getSrc(), dto);
	}

    /**
     * 审核【工单照片】与 更新【照片审核状态】
     *
     * @author liudi
     * @param dto
     */
    @Override
    public void autoAuditOrderPhoto(OrderPhotoDetectionResultDTO dto) throws OmsBaseException {
    	// 拆分数据
	    String[] requestInfoArray = dto.getRequestId().split("-");
	    Long workId = Long.valueOf(requestInfoArray[0]);
	    Long attachmentId = Long.valueOf(requestInfoArray[1]);
	    Integer pictureType = Integer.valueOf(requestInfoArray[2]);

        Map<String, BigDecimal> results = Maps.newHashMapWithExpectedSize(dto.getDetectionResult().size());
        dto.getDetectionResult().forEach(result -> results.put(result.getName(), new BigDecimal(result.getScore()).multiply(new BigDecimal(100))));

		try {
			OrderPhotoDetectionDTO detectionDTO = new OrderPhotoDetectionDTO();
			detectionDTO.setOrderId(workId);
			detectionDTO.setWorkId(workId);
			detectionDTO.setAttachmentId(attachmentId);
			detectionDTO.setPictureType(pictureType);
			detectionDTO.setAuditResultMap(results);
			orderPhotoBService.autoAuditOrderPhoto(detectionDTO);
		} catch (OmsBaseException ex) {
			logger.warn(String.format("工单[{}]自动审核图片验证失败：原因：{}", workId, ex.getMessage()), ex);
		} catch (Exception e) {
			logger.error(String.format("工单[{}]自动审核图片失败：原因：{}", workId, e.getMessage()), e);
		}
    }

	@Override
	@Transactional(rollbackFor = Exception.class)
	@ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_ORDER_PHOTO_AUTO, beforeProceed = false)
	public void autoAuditOrderPhoto(OrderPhotoDetectionDTO detectionDTO) throws OmsBaseException {
		Long orderId = detectionDTO.getOrderId();
		Integer pictureType = detectionDTO.getPictureType();

		OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, detectionDTO.getWorkId());

		// 待更新的附件对象
		OrderAttachment updateAttachment = new OrderAttachment();
		updateAttachment.setAttachmentId(detectionDTO.getAttachmentId());
		updateAttachment.setOrderId(orderId);
		updateAttachment.setReviewerId(detectionDTO.getOperatorId());
		updateAttachment.setReviewTime(DateUtil.getNow());
		updateAttachment.setUpdater(detectionDTO.getOperator());
		updateAttachment.setUpdateTime(DateUtil.getNow());

		ConfOrderAttachmentCategory category = confOrderAttachmentCategoryService.findCategoryById(pictureType);
		if(category != null){
			detectionDTO.setPictureTypeName(category.getCategName());
		} else {
			detectionDTO.setPictureTypeName(OrderAttachmentTypeEnum.getName(pictureType));
		}

		// 审核照片的结果，并将结果设置到 updateAttachment 中
		this.auditPhotoResult(orderWork, updateAttachment, detectionDTO);

		// 更新审核结果
		orderAttachmentService.updateByKey(updateAttachment);

		if (Objects.equals(detectionDTO.getPictureType(), OrderAttachmentTypeEnum.CONSTS_THZ) &&
				Objects.equals(updateAttachment.getReviewStatus(), OrderConsts.IMAGE_REVIEW_STATUS_SUCCESS)) {
			// 修改工单的贴花状态
			OrderWork updateOrderWork = new OrderWork();
			updateOrderWork.setOrderId(detectionDTO.getOrderId());
			updateOrderWork.setWorkId(detectionDTO.getWorkId());
			updateOrderWork.setAppliqueStatus(OrderConsts.IMAGE_REVIEW_STATUS_SUCCESS);
			orderWorkService.updateOrderWorkByKey(updateOrderWork);
		}

		detectionDTO.setAiAuditStatus(updateAttachment.getAiAuditStatus());
		detectionDTO.setReviewStatus(updateAttachment.getReviewStatus());
		detectionDTO.setSrcIndex(updateAttachment.getSrcIndex());
		detectionDTO.setAiAuditDesc(updateAttachment.getAiAuditDesc());

		logger.info("工单[{}]自动审核图片结果：{}", detectionDTO.getWorkId(), JSON.toJSON(detectionDTO));

		// 向APP推送图片审核结果消息
		messageSendAppService.pushAppMessageInfo(MessageConsts.PUSH_MSG_RULEID_ATTACHMENT_AUDIT_RESULT, JSON.toJSONString(detectionDTO), orderWork);
	}

	/**
	 * 审核照片，并将审核的结果设置到 incompleteAttachment 中
	 *
	 * @param orderWork
	 * @param incompleteAttachment 半成品，为了往里面set【照片下标】、【审核结果】、【审核结果说明】
	 * @param detectionDTO
	 * @return
	 * @author liudi
	 * @since: 2022/4/2 11:34
	 */
	@Override
	public void auditPhotoResult(OrderWork orderWork, OrderAttachment incompleteAttachment, OrderPhotoDetectionDTO detectionDTO) throws OmsBaseException {

		// 检查是否可以操作工单照片
		this.checkCanOperation(orderWork);

		OrderAttachment attachment = orderAttachmentService.findAttachmentByKey(incompleteAttachment.getAttachmentId());
		// 组装数据
		incompleteAttachment.setSrcIndex(attachment.getSrcIndex());
		incompleteAttachment.setReviewStatus(attachment.getReviewStatus());

		// 获取照片附件配置
		// 获取照片配置
		OrderAttachmentQuery orderAttachmentQuery = BeanMapper.map(orderWork, OrderAttachmentQuery.class);
		// 后台配置存储的是前台产品
		orderAttachmentQuery.setProductId(orderWork.getShowProductId());
		orderAttachmentQuery.setType(detectionDTO.getPictureType());
		ConfOrderAttachment photoConfigAttachment = confOrderAttachmentBService.getAttachmentConfigByQuery(orderAttachmentQuery);


		// 检查是否同时开启【后台审核】与【自动审核】
		if (!(Objects.equals(photoConfigAttachment.getNeedReview(), GlobalConsts.YES)
				&& Objects.equals(photoConfigAttachment.getAutoAudit(), GlobalConsts.YES))) {
			throw new OmsBaseException(String.format("照片配置ID：[%s]，请确认是否开启了【后台审核】与【自动审核】功能，入参：[%s]", photoConfigAttachment.getId(), detectionDTO));
		}

		// 验证该【照片配置】是否有【审核标准】
		List<ConfOrderAttachmentStandard> standardList = this.getAttachmentStandard(orderWork, photoConfigAttachment);

		// 开始审核
		this.judgeResult(incompleteAttachment, standardList, detectionDTO);
	}

	/**
	 * AI开始审核结果：
	 * 匹配规则与结果，判断是否至少有一组满足,否则返回false
	 * 识别物审核标准条件：
	 * 【每组之间】是or关系；
	 * 【每组内】是and关系；
	 *
	 * @param incompleteAttachment 半成品Attachment
	 * @param standardList         审核标准
	 * @param detectionDTO         审核结果数据
	 * @return
	 */
	private void judgeResult(OrderAttachment incompleteAttachment, List<ConfOrderAttachmentStandard> standardList, OrderPhotoDetectionDTO detectionDTO) throws OmsBaseException {

		// 获取图片审核后的结果
		Map<String, BigDecimal> auditResultMap = detectionDTO.getAuditResultMap();
		if (CollectionUtil.isNullOrEmpty(auditResultMap)) {
			incompleteAttachment.setAiAuditStatus(OrderConsts.IMAGE_REVIEW_STATUS_FAIL);
			String auditStandard = standardList.get(0).getAuditStandard();
			List<ConfOrderAttachmentAuditStandard> auditStandardList = JSON.parseArray(auditStandard, ConfOrderAttachmentAuditStandard.class);
			incompleteAttachment.setAiAuditDesc(String.format("未检出%s", auditStandardList.get(0).getIdentifier()));
			return;
		}


		ResultDTO auditResult = null;
		for (int i = 0; i < standardList.size(); i++) {
			ConfOrderAttachmentStandard standard = standardList.get(i);
			// 后台人员配置的【自动审核标准】
			List<ConfOrderAttachmentAuditStandard> auditStandardList = JSON.parseArray(standard.getAuditStandard(), ConfOrderAttachmentAuditStandard.class);

			// 百度接口返回的识别物信息 与 每组内的【审核标准】进行比较，每组中只要有一个没匹配上说明本组不符合条件；开始遍历下一组。
			auditResult = this.getAuditResult(auditStandardList, auditResultMap);
			if (auditResult.isStatusBool()) {
				// 当【识别物结果】符合【某一组中的审核标准】时，修改AI审核状态为成功
				incompleteAttachment.setAiAuditStatus(OrderConsts.IMAGE_REVIEW_STATUS_SUCCESS);
				incompleteAttachment.setReviewStatus(OrderConsts.IMAGE_REVIEW_STATUS_SUCCESS);
				incompleteAttachment.setAiAuditDesc(auditResult.getMessage());
				return;
			}
		}

		incompleteAttachment.setAiAuditStatus(OrderConsts.IMAGE_REVIEW_STATUS_FAIL);
		incompleteAttachment.setAiAuditDesc(auditResult.getMessage());
	}

	private ResultDTO getAuditResult(List<ConfOrderAttachmentAuditStandard> auditStandardList, Map<String, BigDecimal> auditResultMap) {
		ConfOrderAttachmentAuditStandard confOrderAttachmentAuditStandard = auditStandardList.stream()
				.filter(item -> !auditResultMap.containsKey(item.getIdentifier())
						|| auditResultMap.get(item.getIdentifier()).compareTo(new BigDecimal(item.getScore())) < 0).findAny()
				.orElse(null);

		if (confOrderAttachmentAuditStandard == null) {
			return ResultDTO.success("审核成功");
		}

		if (auditResultMap.containsKey(confOrderAttachmentAuditStandard.getIdentifier())) {
			return ResultDTO.fail(String.format("%s的可信程度小于标准", confOrderAttachmentAuditStandard.getIdentifier()));
		} else {
			return ResultDTO.fail(String.format("未检出%s", confOrderAttachmentAuditStandard.getIdentifier()));
		}

	}

    @Override
    public void sendImageDetectionMessage(Long orderId, Long workId, Long attachmentId, Integer pictureType) {
        String key = String.format("%s_%s", "order_image_detection", orderId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderId", orderId);
        jsonObject.put("workId", workId);
        jsonObject.put("attachmentId", attachmentId);
        jsonObject.put("pictureType", pictureType);
        logger.info("#orderwork#imageDetection#sendMq key : {}  content:{}", key, jsonObject.toJSONString());
        zmnMQSender.send(MqTopicConsts.ZMN_TOPIC_OMS, MessageQueueTagConsts.ORDER_PHOTO_DETECTION_TAG, key, jsonObject.toJSONString());
    }

	/**
	 * 获取照片配置的审核标准
	 *
	 * @param orderWork
	 * @param confOrderAttachment 半成品
	 * @return
	 * @author liudi
	 * @since: 2022/4/2 14:22
	 */
	private List<ConfOrderAttachmentStandard> getAttachmentStandard(OrderWork orderWork, ConfOrderAttachment confOrderAttachment) throws OmsBaseException {
		// 如果没有【附件配置】，直接略过
		if (Objects.isNull(confOrderAttachment)) {
			String message = String.format("工单[%s]对应渠道[%s]无照片配置，无需操作工单照片", orderWork.getOrderId(), orderWork.getChannelId());
			logger.error(message);
			throw new OmsBaseException(message);
		}

		ConfOrderAttachmentStandard standardQuery = new ConfOrderAttachmentStandard();
		standardQuery.setConfAttachmentId(confOrderAttachment.getId());
		logger.info("自动审核 - 查询配置的审核标准【listByAttachmentIds】 入参：{}", confOrderAttachment.getId());
		List<ConfOrderAttachmentStandard> standardList = confOrderAttachmentStandardService.listByQuery(standardQuery);
		logger.info("自动审核 - 查询配置的审核标准【listByAttachmentIds】 出参：{}", standardList);

		// 如果没有配置【审核标准】，直接略过
		if (CollectionUtil.isNullOrEmpty(standardList)) {
			String message = String.format("工单[%s]对应照片配置ID：[%s]未配置审核标准，无需操作工单照片", orderWork.getOrderId(), confOrderAttachment.getId());
			logger.error(message);
			throw new OmsBaseException(message);
		}

		return standardList;
	}

	/**
	 * 检查该工单是否可操作
	 *
	 * @param orderWork
	 * @throws OmsBaseException
	 * @author liudi
	 * @since: 2022/4/1 15:44
	 */
	private void checkCanOperation(OrderWork orderWork) throws OmsBaseException {
		String rejectReason = "";

		// 1、退款单，不可操作
		if (Objects.equals(OrderConsts.ORDER_TYPE_REFUND, orderWork.getType())) {
			rejectReason = String.format("工单[%s]为退款单，无需操作工单照片", orderWork.getOrderId());
		}

		// 2、赔偿单，不可操作
		if (Objects.equals(OrderConsts.ORDER_TYPE_COMPENSATE, orderWork.getType())) {
			rejectReason = String.format("工单[%s]为赔偿单，无需操作工单照片", orderWork.getOrderId());
		}

		// 3、派单后，可操作
		if (orderWork.getStatus() < OrderStatusConsts.WORK_STATUS_DISTRIBUTE) {
			rejectReason = String.format("工单[%s]未派单，无需操作工单照片", orderWork.getOrderId());
		}

		if (StringUtils.isNotBlank(rejectReason)) {
			throw new OmsBaseException(rejectReason);
		}
	}


	/**
	 * 发送图片检测请求
	 * @param imageUrl
	 * @return
	 */
	private void sendRequest(String imageUrl, OrderPhotoDetectionDTO dto) {
		String urlMD5 = null;
		try {
			urlMD5 = MD5Utils.getMD5For32UTF8(imageUrl);
		} catch (Exception e) {
			logger.error("图片地址编码报错", e);
		}

		String requestId = String.format(REQUEST_ID_FORMAT, dto.getWorkId(), dto.getAttachmentId(), dto.getPictureType(), urlMD5);

		// 发送自动审核请求
		ImageDetectionDIO imageDetectionDIO = new ImageDetectionDIO();
		imageDetectionDIO.setRequestId(requestId);
		imageDetectionDIO.setImageUrl(imageUrl);
		imageDetectionDIO.setScene(ImageDetectionConsts.SCENE_TYPE_VISIT);
		imageDetectionDIO.setNotifyTopic(MqTopicConsts.ZMN_TOPIC_OMS);
		imageDetectionDIO.setNotifyTag(MessageQueueTagConsts.ORDER_PHOTO_DETECTION_CALLBACK_TAG);
		logger.info("请求图片检测接口：入参:{}", JSON.toJSONString(imageDetectionDIO));
		ResponseDTO responseDTO = imageDetectionRemoteService.asyncImageDetection(imageDetectionDIO);
		logger.info("请求图片检测接口：出参:{}", JSON.toJSONString(responseDTO));
	}

}
